package worldobjects;

import java.awt.Color;

import raytracing.Ray;
import raytracing.RaycastResult;
import structs.StandardValues;
import structs.Vector3;

public class Sphere implements IWorldObject {
	public Vector3 center;
	public float radius;
	public Color diffuseColor;
	public Color specularColor;
	public float specularIntensity;
	public boolean reflective;
	public boolean castsShadows = true;
	public float selfIllumination = 1;
	/* SELF ILLUMINATION NOTE:
	 * range [0..infinity], will be multiplied with the final calculated color
	 * 0 means this object will appear black.
	 * 1 means this objects has no 'self illumination'
	 */
	
	public Sphere(Vector3 pos, float rad) {
		center = pos;
		radius = rad;
		diffuseColor = StandardValues.DIFFUSE_COLOR;
		specularColor = StandardValues.SPECULAR_COLOR;
		specularIntensity = StandardValues.SPECULAR_INTENSITY;
	}

	@Override
	public boolean isHit(Ray ray, float minDist, float maxDist, RaycastResult result) {
		result.distance = Integer.MAX_VALUE;

		Vector3 eMinusc = ray.Origin.plus(center.multiply(-1));
		float discriminantOver4 = ray.Direction.dotproduct(eMinusc) * ray.Direction.dotproduct(eMinusc) - ray.Direction.dotproduct(ray.Direction) * (eMinusc.dotproduct(eMinusc) - radius * radius);

		if (discriminantOver4 < 0)
			return false;

		float dist01 = (ray.Direction.multiply(-1).dotproduct(eMinusc) + (float) Math.sqrt(discriminantOver4)) / ray.Direction.dotproduct(ray.Direction);
		float dist02 = (ray.Direction.multiply(-1).dotproduct(eMinusc) - (float) Math.sqrt(discriminantOver4)) / ray.Direction.dotproduct(ray.Direction);

		
		if(dist01<0 && dist02<0)
			return false;
		
		if (dist01 > minDist && dist01 < dist02 && dist01 < maxDist)
			result.distance = dist01;
		else if (dist02 > minDist && dist02 < dist01 && dist02 < maxDist)
			result.distance = dist02;

		if (result.distance < minDist || result.distance >= maxDist)
			return false;

		result.ray = ray;
		result.normal = calculateNormal(ray.Origin.plus(ray.Direction.multiply(result.distance)));

		result.diffuseColor = diffuseColor;
		result.specularColor = specularColor;
		result.specularIntensity = specularIntensity;
		result.reflective = reflective;
		result.selfllumination = selfIllumination;

		return true;
	}

	private Vector3 calculateNormal(Vector3 intersectPoint) {
		Vector3 normal = intersectPoint.plus(center.multiply(-1));
		normal.normalize();
		return normal;
	}

	@Override
	public BoundingBox getBoundingBox() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean castsShadow() {
		return castsShadows;
	}

}
